package com.yuntsg.ruiijn.database_interior.service;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yuntsg.nnsfcp.common.utils.UserUtil;
import com.yuntsg.ruiijn.database_interior.entity.FileDetailsInterior;
import com.yuntsg.ruiijn.database_interior.entity.FileRecordInterior;
import com.yuntsg.ruiijn.database_interior.entity.InitConfig;
import com.yuntsg.ruiijn.databse_search.entity.FileDetails;
import com.yuntsg.ruiijn.databse_search.entity.NcbiPdfToJpg;
import com.yuntsg.ruiijn.databse_search.service.BussService;
import common.bean.RRException;
import common.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.*;


@Slf4j
@Service
@SuppressWarnings("all")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PdfInteriorService {

    private final FileRecordInteriorService fileRecordService;

    private final FileDetailInteriorService fileDetailService;

    private final CutImageUtil cutImageUtil;

    private final MinioUtil minioUtil;

    private final BussService bussService;

    @Resource
    UserUtil userUtil;

    public static List<ImageInfo> pdftoImages(String directory, String pdfname) {
        List<ImageInfo> imageInfos = new ArrayList<ImageInfo>();
        try {
            ProcessBuilder processBuilder = new ProcessBuilder();
            processBuilder.directory(new File(directory));
            processBuilder.command("/usr/local/bin/mutool", "extract", "-r", pdfname);
//            processBuilder.command("/mnt/ramdisk/mutool", "extract", pdfname);
            processBuilder.redirectErrorStream(true);
            Process process = processBuilder.start();
            InputStream inputStream = process.getInputStream();
            IoUtil.read(inputStream, "utf-8");
            inputStream.close();
            File[] fileList = new File(directory).listFiles();
            for (File file : fileList) {
                byte[] bytes = null;
                String n = file.getName().toLowerCase();
                if (n.endsWith(".jpeg2000") || n.endsWith(".jpg") || n.endsWith(".tiff") || n.endsWith(".bmp") || n.endsWith(".pcx") || n.endsWith(".gif") || n.endsWith(".wbmp") || n.endsWith(".png") || n.endsWith(".raw") || n.endsWith(".jpeg") || n.endsWith(".pnm") || n.endsWith(".tif") || n.endsWith(".jbig2") || n.endsWith(".jpg2")) {
                    if (n.endsWith(".jpg") || n.endsWith(".jpeg")) {
                        bytes = FileUtil.readBytes(file);
                    } else {
                        ByteArrayOutputStream bos = null;
                        try {
                            BufferedImage originalImage = ImageIO.read(file);
                            bos = new ByteArrayOutputStream();
                            ImageIO.write(ensureOpaque(originalImage), "jpg", bos);
                            bos.flush();
                            bytes = bos.toByteArray();
                        } catch (Exception e) {
                            System.out.println("bos_err_a");
                        } finally {
                            if (bos != null) {
                                try {
                                    bos.close();
                                } catch (Exception e) {
                                    System.out.println("bos_err_b");
                                }
                            }
                        }
                    }

                    if (bytes != null) {
                        ImageInfo imageInfo = new ImageInfo();
                        imageInfo.setBytes(bytes);
                        imageInfo.setMd5(new MD5().digestHex(bytes));
                        imageInfo.setName(file.getName().substring(0, file.getName().lastIndexOf(".")) + ".jpg");
                        imageInfos.add(imageInfo);
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return imageInfos;
    }

    static BufferedImage ensureOpaque(BufferedImage bi) {
        if (bi.getTransparency() == BufferedImage.OPAQUE) {
            return bi;
        }
        int w = bi.getWidth();
        int h = bi.getHeight();
        int[] pixels = new int[w * h];
        bi.getRGB(0, 0, w, h, pixels, 0, w);
        BufferedImage bi2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        bi2.setRGB(0, 0, w, h, pixels, 0, w);
        return bi2;
    }

    public boolean downLoad(String key, Integer type) throws IOException {

        long count = fileRecordService.count(Wrappers.<FileRecordInterior>lambdaQuery().eq(FileRecordInterior::getPmut, key));
        if (count > 0) {
            throw new RRException("文献已经下载，请勿重复操作！！");
        }

        String pdfUrl = "";
        String fileName = "";
        String abase64 = XXTEA.encryptToBase64String(key + "", "R0HWlCI3ndd1s8S3");
        String url = StrUtil.format("https://www.pubtsg.com/api/getpdfurl.do?unitid=1&type={}&query={}", type, abase64);
        String html = HttpUtil.get(url);
        if (StrUtil.isNotBlank(html)) {
            JSONObject jsonObject = JSONUtil.parseObj(html);
            int flag = (int) jsonObject.get("flag");
            if (flag == 1) {
                String pdfPath = (String) jsonObject.get("pdfurl");
                Map<String, String> encryptMap = encryptPdf(pdfPath, 1, 1);
                pdfUrl = encryptMap.get("pdfUrl");
                fileName = encryptMap.get("fileName");
            }
        } else {
            throw new RRException("没有全文信息");
        }
        if (StrUtil.isEmpty(fileName)) {
            fileName = RandomUtil.randomString(10) + ".pdf";
        }

        String randomStr = RandomUtil.randomString(4) + "/";
        long size = HttpUtil.downloadFile(pdfUrl, InitConfig.tempPdfPath + randomStr + fileName);

        if (size > 0) {
            String md5 = SecureUtil.md5(FileUtil.getInputStream(InitConfig.tempPdfPath + randomStr + fileName));
            String ossPath = minioUtil.upload(FileUtil.getInputStream(InitConfig.tempPdfPath + randomStr + fileName), fileName, userUtil.getUidStr());
            FileRecordInterior fileRecord = new FileRecordInterior().setType(2)
                    .setPmut(key)
                    .setTitle(fileName)
                    .setFilePath(InitConfig.tempPdfPath + randomStr)
                    .setOssPath(ossPath)
                    .setUploadId(userUtil.getUidStr())
                    .setUploadTime(DateUtil.date().getTime())
                    .setExStatus(0)
                    .setMd5(md5);
            fileRecordService.saveOrUpdate(fileRecord);
        } else {
            return false;
        }
        return true;
    }

    public boolean upload(MultipartFile file, String title, String author, String pmut) throws IOException {

        FileRecordInterior one = fileRecordService.getOne(Wrappers.<FileRecordInterior>lambdaQuery().eq(FileRecordInterior::getMd5, SecureUtil.md5(file.getInputStream())));
        if (null != one) {
            throw new RRException("文献已经存在，请勿重复操作！！ 重复rid:" + one.getId());
        }

        String randomStr = RandomUtil.randomString(4) + "/";
        FileUtil.writeFromStream(file.getInputStream(), InitConfig.tempPdfPath + randomStr + title);

        String md5 = SecureUtil.md5(FileUtil.getInputStream(InitConfig.tempPdfPath + randomStr + title));
        String ossPath = minioUtil.upload(FileUtil.getInputStream(InitConfig.tempPdfPath + randomStr + title), title, userUtil.getUidStr());
        FileRecordInterior fileRecord = new FileRecordInterior().setType(2)
                .setPmut(pmut)
                .setTitle(title)
                .setFilePath(InitConfig.tempPdfPath + randomStr)
                .setOssPath(ossPath)
                .setUploadId(userUtil.getUidStr())
                .setUploadTime(DateUtil.date().getTime())
                .setExStatus(0)
                .setMd5(md5);
        fileRecordService.saveOrUpdate(fileRecord);

        return true;
    }

    /**
     * 提取图片
     *
     * @param key  pmUt
     * @param type 0 pm，1 ut
     */
    public boolean extract(Integer rid) throws IOException {
        String tableMark = "ncbi_pdf_to_jpg_9998";
        FileRecordInterior record = fileRecordService.getById(rid);
        if (record.getExStatus() == 1) {
            throw new RRException("文章已经拆分,请勿重复操作");
        }
        String filePath = record.getFilePath();
        List<FileDetailsInterior> fileDetails = extractPdf(record.getFilePath(), record.getTitle(), rid);

        log.info("拆分图片数量{}", fileDetails.size());
        if (fileDetails.size() == 0) {
            return false;
        }
        fileDetails.stream().forEach(f -> {
            fileDetailService.saveOrUpdate(f.setRid(rid));
            List<FileDetails> normalSplitting = cutImageUtil.workNoUid(f.getPath(), f.getId(), f.getRid(), -1, 0);
            List<FileDetails> fineSplitting = cutImageUtil.workfiligreeNoId(f.getPath(), f.getId(), f.getRid(), -1, 0);
            log.info("拆出来的普通图片数量为___" + normalSplitting.size());
            if (normalSplitting.size() > 0) {
                fileDetailService.saveOrUpdateBatch(ConvertUtils.convertUnite(FileDetailsInterior.class, normalSplitting));

            }
            log.info("拆出来的精细图片数量为___" + fineSplitting.size());
            if (fineSplitting.size() > 0) {
                fileDetailService.saveOrUpdateBatch(ConvertUtils.convertUnite(FileDetailsInterior.class, fineSplitting));
            }
            NcbiPdfToJpg ncbiPdfToJpg = new NcbiPdfToJpg();
            ncbiPdfToJpg.setPmidUt(record.getPmut());
            ncbiPdfToJpg.setFileName(StrUtil.subAfter(f.getPath(), "/", true));
            ncbiPdfToJpg.setFigureZip(minioUtil.downloadByte(f.getPath()));
            ncbiPdfToJpg.setFigureMd5("");
            ncbiPdfToJpg.setStatus(0);
            fileDetailService.saveOrUpdate(f.setSplitStatus(0).setSerialId(bussService.saveOrUpdate(tableMark, Arrays.asList(ncbiPdfToJpg))).setTableNo(9998));
        });
        fileRecordService.saveOrUpdate(record.setExStatus(1).setExId(userUtil.getUidStr()).setExTime(System.currentTimeMillis()));
        return true;
    }

    public List<FileDetailsInterior> extractPdf(String path, String tempName, Integer rid) throws IOException {
        List<FileDetailsInterior> fileDetailsSelfs = new ArrayList<FileDetailsInterior>();

        List<ImageInfo> imageInfos = pdftoImages(path, path + tempName);
        for (ImageInfo imageInfo : imageInfos) {
            FileDetailsInterior fileDetails = new FileDetailsInterior();
            fileDetails.setFId(rid);
            fileDetails.setTpye(2);
            String name = imageInfo.getName();
            BufferedImage image = ImgUtil.read(new ByteArrayInputStream(imageInfo.getBytes()));
            String jpg = "";
            if (image.getHeight() > 2000 || image.getWidth() > 2000) {
                Image img = null;
                try {
                    img = ImgUtil.scale(image, 0.4f);
                } catch (Exception e) {
                    continue;
                }
                jpg = minioUtil.upload(ImgUtil.toStream(img, "jpg"), name, userUtil.getUidStr());
            } else {
                jpg = minioUtil.upload(bufferedImageToInputStream(image), name, userUtil.getUidStr());
            }
            if (null != jpg && StrUtil.isNotEmpty(jpg)) {
                fileDetails.setPath(jpg);
            } else {
                continue;
            }
            fileDetailsSelfs.add(fileDetails);
        }

        return fileDetailsSelfs;
    }

    public Map<String, String> encryptPdf(String pdfpath, Integer uid, Integer gid) {
        Map<String, String> map = new HashMap<>();
        if (StrUtil.isNotBlank(pdfpath)) {
            String[] prevEncryptStrArray = pdfpath.split(",");
            String encoderFileName = "";
            String encryptQuery = "";
            String preEncryptStr = "";
            //link是用来返回pc端申请全文时候的一个加密pdf地址。
            String links = "";
            for (String str : prevEncryptStrArray) {
//                if (!str.contains("|pdf")) {
//                    continue;
//                }
                String[] array = str.split("\\|");
                preEncryptStr = array[0] + "|" + array[1] + "|" + array[2];
                String fileName = "show";
                if (array.length > 3) {
                    //给str赋值去掉文件名的待加密字符串
                    str = str.replace("|" + array[3], "");
                    fileName = array[3].replace("#_#", ".");
                }
                String encryptStrPre = uid + "|" + gid + "|" + str + "|" + System.currentTimeMillis();
                encryptQuery = XXTEASafe.encryptToBase64String(encryptStrPre, "VJpHo2naZ9");
                String urlKeyStr = "pdfUrl";
                String suffix = ".pdf";
                if (str.contains("rar")) {
                    suffix = ".rar";
                    urlKeyStr = "rarUrl";
                }
                encoderFileName = URLEncoder.encode(fileName).replace("+", "%20");
                String newLink = "https://attach.pubtsg.com/attach/" + encoderFileName + "?query=" + encryptQuery + "&view=true&type=" + suffix;
                map.put(urlKeyStr, newLink);
            }
            if (links.length() > 1) {
                links = links.substring(1);
            }
            String keyMd5 = SecureUtil.md5(preEncryptStr);
            String keyHex = HexUtil.encodeHexStr(SecureUtil.md5(keyMd5 + "qf3.1415"));
//            log.info("当前查看的全文全文id:" + casesid + "--用户:" + uid + "--pdfpath:" + pdfpath + "---" + preEncryptStr + "---" + keyMd5 + "---" + keyHex);
            map.put("str", keyMd5);
            map.put("keyHex", keyHex);
            map.put("fileName", encoderFileName);
            map.put("query", encryptQuery);
            map.put("links", links);
        }
        return map;
    }

    /**
     * 将BufferedImage转换为InputStream
     *
     * @param image
     * @return
     */
    public InputStream bufferedImageToInputStream(BufferedImage image) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
            InputStream input = new ByteArrayInputStream(os.toByteArray());
            return input;
        } catch (IOException e) {

        }
        return null;
    }
}
